home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / amiga / ujoin101.lzh / xbin.c < prev   
C/C++ Source or Header  |  1990-08-31  |  22KB  |  1,104 lines

  1. #ifndef lint
  2. static char version[] = "xbin.c Version 3.0 09/30/89";
  3. #endif lint
  4. #include <stdio.h>
  5. #include <errno.h>
  6.  
  7. #ifndef    MPW
  8. #   include <stdlib.h>
  9. #   include <fcntl.h>
  10. #   include <string.h>
  11. #   ifdef AZTEC_C
  12. #       include <stat.h>
  13. #       include <time.h>
  14. #   endif
  15. #   ifndef AMIGA
  16. #       include <sys/types.h>
  17. #       include <sys/stat.h>
  18. #       include <sys/dir.h>
  19. #   endif /* AMIGA */
  20. #else    MPW
  21. #   include <Types.h>
  22. #   include <Files.h>
  23. #   include <Memory.h>
  24. #   include <ErrMgr.h>
  25. #   include <StdLib.h>
  26. #   include <String.h>
  27. #   include <CursorCtl.h>
  28. #   define     FALSE 0
  29. #   define     TRUE 1
  30.     /* stops linker linking these in */
  31.     ecvt() {}
  32.     fcvt() {}
  33. #endif    MPW
  34. extern int errno;
  35.  
  36. #ifndef TRUE
  37. #   define TRUE    1
  38. #   define FALSE   0
  39. #endif
  40.  
  41. #ifdef MAXNAMLEN    /* 4.2 BSD */
  42. #define FNAMELEN MAXNAMLEN
  43. #else
  44. #define FNAMELEN DIRSIZ
  45. #endif
  46.  
  47. #ifdef BSD
  48. #include <sys/time.h>
  49. #include <sys/timeb.h>
  50. #define search_last rindex
  51. extern char *rindex();
  52. #else
  53. #include <time.h>
  54. #ifndef AZTEC_C
  55. extern long timezone;
  56. #endif
  57. #define search_last strrchr
  58. extern char *strrchr();
  59. #endif
  60.  
  61. /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  62. #define TIMEDIFF 0x7c25b080
  63.  
  64. #define DATABYTES 128
  65.  
  66. #define BYTEMASK 0xff
  67. #define BYTEBIT 0x100
  68. #define WORDMASK 0xffff
  69. #define WORDBIT 0x10000
  70.  
  71. #define NAMEBYTES 63
  72. #define H_NLENOFF 1
  73. #define H_NAMEOFF 2
  74.  
  75. /* 65 <-> 80 is the FInfo structure */
  76. #define H_TYPEOFF 65
  77. #define H_AUTHOFF 69
  78. #define H_FLAGOFF 73
  79.  
  80. #define H_LOCKOFF 81
  81. #define H_DLENOFF 83
  82. #define H_RLENOFF 87
  83. #define H_CTIMOFF 91
  84. #define H_MTIMOFF 95
  85.  
  86. #define H_OLD_DLENOFF 81
  87. #define H_OLD_RLENOFF 85
  88.  
  89. #define F_BUNDLE 0x2000
  90. #define F_LOCKED 0x8000
  91.  
  92. struct macheader {
  93.     char m_name[NAMEBYTES+1];
  94.     char m_type[4];
  95.     char m_author[4];
  96.     short m_flags;
  97.     long m_datalen;
  98.     long m_rsrclen;
  99.     long m_createtime;
  100.     long m_modifytime;
  101. } mh;
  102.  
  103. struct filenames {
  104.     char f_info[256];
  105.     char f_data[256];
  106.     char f_rsrc[256];
  107. } files;
  108.  
  109. /* Prototypes: */
  110. int setup_files(char *filename, char *macname);
  111. int print_header(void);
  112. int process_forks(void);
  113. int forge_info(void);
  114. int find_header(void);
  115. int do_q_header(char *macname);
  116. int do_q_fork(char *fname, long len, int dataFork);
  117. int verify_crc(unsigned int calc_crc, unsigned int file_crc);
  118. int q_init(void);
  119. short get2q(void);
  120. long get4q(void);
  121. int getqbuf(char *buf, int n);
  122. int getq(void);
  123. int getq_nocrc(void);
  124. int getq_raw(void);
  125. int get6bits(void);
  126. int comp_q_crc(unsigned int c);
  127. int do_o_header(char *macname, char *filename);
  128. int do_o_forks(void);
  129. long make_file(char *fname, int compressed);
  130. int comp_c_crc(int c);
  131. int comp_e_crc(int c);
  132. int comp_to_bin(char *ibuf, struct __stdio *outf);
  133. int hex_to_bin(char *ibuf, struct __stdio *outf);
  134. int hexit(int c);
  135. int put2(char *bp, short value);
  136. int put4(char *bp, long value);
  137.  
  138. /* Global data: */
  139.  
  140. int pre_beta;    /* options */
  141. int listmode;
  142. int verbose;
  143.  
  144. int compressed;    /* state variables */
  145. int qformat;
  146. FILE *ifp;
  147. long get4q();
  148.  
  149. /*
  150.  * xbin -- unpack BinHex format file into suitable
  151.  * format for downloading with macput
  152.  * Dave Johnson, Brown University Computer Science
  153.  *
  154.  * (c) 1984 Brown University
  155.  * may be used but not sold without permission
  156.  *
  157.  * created ddj 12/16/84
  158.  * revised ddj 03/10/85 -- version 4.0 compatibility, other minor mods
  159.  * revised ddj 03/11/85 -- strip LOCKED bit from m_flags
  160.  * revised ahm 03/12/85 -- System V compatibility
  161.  * revised dba 03/16/85 -- (Darin Adler, TMQ Software)  4.0 EOF fixed,
  162.  *               4.0 checksum added
  163.  * revised ddj 03/17/85 -- extend new features to older formats: -l, stdin
  164.  * revised ddj 03/24/85 -- check for filename truncation, allow multiple files
  165.  * revised ddj 03/26/85 -- fixed USG botches, many problems w/multiple files
  166.  * revised jcb 03/30/85 -- (Jim Budler, amdcad!jimb), revised for compatibility
  167.  *               with 16-bit int machines
  168.  * revised dl  06/16/85 -- (Dan LaLiberte, liberte@uiucdcs) character
  169.  *               translation speedup
  170.  * revised ddj 09/30/85 -- fixed problem with run of RUNCHAR
  171.  * revised sw  09/30/89 -- much hacked about to work with MPW
  172.  * revised mrr 08/31/90 -- concessions to the Amiga and Aztec C (5.0b)
  173.  */
  174. char usage[] = "usage: \"xbin [-v] [-l] [-o] [-n name] [-] filename\"\n";
  175.  
  176. main(ac, av)
  177. char **av;
  178. {
  179.     char *filename, *macname;
  180.  
  181. #ifdef    MPW
  182.     InitCursorCtl(nil);
  183. #endif    MPW
  184.     filename = ""; macname = "";
  185.     ac--; av++;
  186.     while (ac) {
  187.         if (av[0][0] == '-') {
  188.             switch (av[0][1]) {
  189.             case '\0':
  190.                 filename = "-";
  191.                 break;
  192.             case 'v':
  193.                 verbose++;
  194.                 break;
  195.             case 'l':
  196.                 listmode++;
  197.                 break;
  198.             case 'o':
  199.                 pre_beta++;
  200.                 break;
  201.             case 'n':
  202.                 if (ac > 1) {
  203.                     ac--; av++;
  204.                     macname = av[0];
  205.                     filename = "";
  206.                     break;
  207.                 }
  208.                 else
  209.                     goto bad_usage;
  210.             default:
  211.                 goto bad_usage;
  212.             }
  213.         }
  214.         else
  215.             filename = av[0];
  216.         if (filename[0] != '\0') {
  217.             setup_files(filename, macname);
  218.             if (listmode) {
  219.                 print_header();
  220.             }
  221.             else {
  222.                 process_forks();
  223.                 /* now that we know the size of the forks */
  224.                 forge_info();
  225.             }
  226.             if (ifp != stdin)
  227.                 fclose(ifp);
  228.             macname = "";
  229.             ifp = NULL;        /* reset state */
  230.             qformat = 0;
  231.             compressed = 0;
  232.         }
  233.         ac--; av++;
  234.     }
  235.     if (*filename == '\0') {
  236. bad_usage:
  237.         fprintf(stderr, usage);
  238.         exit(1);
  239.     }
  240. }
  241.  
  242. static char *extensions[] = {
  243.     ".hqx",
  244.     ".hcx",
  245.     ".hex",
  246.     "",
  247.     NULL
  248. };
  249.  
  250. setup_files(filename, macname)
  251. char *filename;        /* input file name -- extension optional */
  252. char *macname;        /* name to use on the mac side of things */
  253. {
  254.     char **ep;
  255.     char namebuf[256];
  256. #ifndef    MPW
  257.     int n;
  258.     char *np;
  259.     struct stat stbuf;
  260. #else    MPW
  261.     FInfo    finderInfo;
  262. #endif    MPW
  263.     long curtime;
  264. #ifdef    MPW
  265.     OSType    f_creator, f_type;
  266. #endif    MPW
  267.  
  268.     if (filename[0] == '-') {
  269.         ifp = stdin;
  270. #ifdef    MPW
  271.         filename = "Dev:Stdin";
  272. #else    MPW
  273.         filename = "stdin";
  274. #endif    MPW
  275.         strcpy (namebuf, filename);
  276.     }
  277.     else {
  278.         /* find input file and open it */
  279.         for (ep = extensions; *ep != NULL; ep++) {
  280.             sprintf(namebuf, "%s%s", filename, *ep);
  281. #ifndef    MPW
  282.             if (stat(namebuf, &stbuf) == 0)
  283.                 break;
  284. #else    MPW
  285.             c2pstr(namebuf);
  286.             if (GetFInfo (namebuf, 0, &finderInfo) == noErr) {
  287.                 p2cstr(namebuf);
  288.                 break;
  289.             }
  290.             p2cstr(namebuf);
  291. #endif    MPW
  292.         }
  293.         if (*ep == NULL) {
  294.             perror(namebuf);
  295.             exit(-1);
  296.         }
  297.         ifp = fopen(namebuf, "r");
  298.         if (ifp == NULL) {
  299.             perror(namebuf);
  300.             exit(-1);
  301.         }
  302.     }
  303.     if (ifp == stdin) {
  304.         curtime = time(0);
  305.         mh.m_createtime = curtime;
  306.         mh.m_modifytime = curtime;
  307.     }
  308.     else {
  309. #ifndef    MPW
  310.         mh.m_createtime = stbuf.st_mtime;
  311.         mh.m_modifytime = stbuf.st_mtime;
  312. #endif    MPW
  313.     }
  314.     if (listmode || verbose) {
  315.         fprintf(stderr, "%s %s%s",
  316.             listmode ? "Listing" : "Converting",
  317.             namebuf, listmode ? ":\n" : " ");
  318.     }
  319.     qformat = find_header(); /* eat mailer header &cetera, intuit format */
  320.  
  321.     if (qformat)
  322.         do_q_header(macname);
  323.     else
  324.         do_o_header(macname, filename);
  325.  
  326. #ifndef    MPW
  327.     /* make sure host file name doesn't get truncated beyond recognition */
  328.     n = strlen(mh.m_name);
  329.     if (n > FNAMELEN - 2)
  330.         n = FNAMELEN - 2;
  331.     strncpy(namebuf, mh.m_name, n);
  332.     namebuf[n] = '\0';
  333.     /* get rid of troublesome characters */
  334.     for (np = namebuf; *np; np++)
  335.         if (*np <= ' ' || *np == '/' || *np >= '\177')
  336.             *np = '_';
  337.  
  338.     sprintf(files.f_data, "%s.data", namebuf);
  339.     sprintf(files.f_rsrc, "%s.rsrc", namebuf);
  340.     sprintf(files.f_info, "%s.info", namebuf);
  341.     if (verbose)
  342.         fprintf(stderr, "==> %s.{info,data,rsrc}\n", namebuf);
  343. #else    MPW
  344.     if (verbose)
  345.         fprintf(stderr, "==> \"%s\"\n", mh.m_name);
  346.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  347.     BlockMove (mh.m_type, (char *)&f_type, 4);
  348.     c2pstr(mh.m_name);
  349.     (void)Create (mh.m_name, 0, f_creator, f_type);
  350.     p2cstr(mh.m_name);
  351. #endif    MPW
  352. }
  353.  
  354. /* print out header information in human-readable format */
  355. print_header()
  356. {
  357.  
  358.     printf("macname: %s\n", mh.m_name);
  359.     printf("filetype: %.4s, ", mh.m_type);
  360.     printf("author: %.4s, ", mh.m_author);
  361.     printf("flags: 0x%x\n", mh.m_flags);
  362.     if (qformat) {
  363.         printf("data length: %ld, ", mh.m_datalen);
  364.         printf("rsrc length: %ld\n", mh.m_rsrclen);
  365.     }
  366.     if (!pre_beta) {
  367.         printf("create time: %s", ctime((time_t *) &mh.m_createtime));
  368.     }
  369. }
  370.  
  371. process_forks()
  372. {
  373.     if (qformat) {
  374.         /* read data and resource forks of .hqx file */
  375. #ifdef    MPW
  376.         do_q_fork(mh.m_name, mh.m_datalen, TRUE);
  377.         do_q_fork(mh.m_name, mh.m_rsrclen, FALSE);
  378. #else    MPW
  379.         if (mh.m_datalen > 0)
  380.             do_q_fork(files.f_data, mh.m_datalen, TRUE);
  381.         if (mh.m_rsrclen > 0)
  382.             do_q_fork(files.f_rsrc, mh.m_rsrclen, FALSE);
  383. #endif    MPW
  384.     }
  385.     else
  386.         do_o_forks();
  387. }
  388.  
  389. /* write out .info file from information in the mh structure */
  390. forge_info()
  391. {
  392.     static char buf[DATABYTES];
  393. #ifndef    MPW
  394.     char *np;
  395.     FILE *fp;
  396.     int n;
  397.     long tdiff;
  398.     struct tm *tp;
  399. #ifdef BSD
  400.     struct timeb tbuf;
  401. #else
  402.     time_t bs;
  403. #endif
  404.     for (np = mh.m_name; *np; np++)
  405.         if (*np == '_') *np = ' ';
  406.  
  407.     buf[H_NLENOFF] = n = np - mh.m_name;
  408.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  409.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  410.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  411.     put2(buf + H_FLAGOFF, mh.m_flags & ~F_LOCKED);
  412.     if (pre_beta) {
  413.         put4(buf + H_OLD_DLENOFF, mh.m_datalen);
  414.         put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
  415.     }
  416.     else {
  417.         put4(buf + H_DLENOFF, mh.m_datalen);
  418.         put4(buf + H_RLENOFF, mh.m_rsrclen);
  419.  
  420.         /* convert unix file time to mac time format */
  421. #ifdef BSD
  422.         ftime(&tbuf);
  423.         tp = localtime(&tbuf.time);
  424.         tdiff = TIMEDIFF - tbuf.timezone * 60;
  425.         if (tp->tm_isdst)
  426.             tdiff += 60 * 60;
  427. #else
  428.         /* I hope this is right! -andy */
  429.         time(&bs);
  430.         tp = localtime(&bs);
  431. #ifdef AZTEC_C
  432.         tdiff = TIMEDIFF;
  433. #else
  434.         tdiff = TIMEDIFF - timezone;
  435. #endif
  436.         if (tp->tm_isdst)
  437.             tdiff += 60 * 60;
  438. #endif
  439.         put4(buf + H_CTIMOFF, mh.m_createtime + tdiff);
  440.         put4(buf + H_MTIMOFF, mh.m_modifytime + tdiff);
  441.     }
  442.     fp = fopen(files.f_info, "w");
  443.     if (fp == NULL) {
  444.         perror("info file");
  445.         exit(-1);
  446.     }
  447.     fwrite(buf, 1, DATABYTES, fp);
  448.     fclose(fp);
  449. #else    MPW
  450.     ParamBlockRec    pb;
  451.  
  452.     strcpy (buf, mh.m_name);
  453.     c2pstr (buf);
  454.     pb.fileParam.ioNamePtr = buf;
  455.     pb.fileParam.ioVRefNum = 0;
  456.     pb.fileParam.ioFVersNum = 0;
  457.     pb.fileParam.ioFDirIndex = 0;
  458.     pb.fileParam.ioResult = 0;
  459.     (void)PBGetFInfo (&pb, FALSE);
  460.     
  461.     pb.fileParam.ioFlFndrInfo.fdFlags = mh.m_flags;
  462. /*
  463.     pb.ioFlCrDat = mh.m_createtime;
  464.     pb.ioFlMdDat = mh.m_modifytime;
  465. */    
  466.     (void)PBSetFInfo (&pb, FALSE);
  467.     
  468. #endif    MPW
  469. }
  470.  
  471. /* eat characters until header detected, return which format */
  472. find_header()
  473. {
  474.     int c, at_bol;
  475.     char ibuf[BUFSIZ];
  476.  
  477.     /* look for "(This file ...)" line */
  478.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  479.         if (strncmp(ibuf, "(This file", 10) == 0)
  480.             break;
  481.     }
  482.     at_bol = 1;
  483.     while ((c = fgetc(ifp)) != EOF) {
  484.         switch (c) {
  485.         case '\n':
  486.         case '\r':
  487.             at_bol = 1;
  488.             break;
  489.         case ':':
  490.             if (at_bol)    /* q format */
  491.                 return 1;
  492.             break;
  493.         case '#':
  494.             if (at_bol) {    /* old format */
  495.                 ungetc(c, ifp);
  496.                 return 0;
  497.             }
  498.             break;
  499.         default:
  500.             at_bol = 0;
  501.             break;
  502.         }
  503.     }
  504.  
  505.     fprintf(stderr, "unexpected EOF\n");
  506.     exit(2);
  507.     /* NOTREACHED */
  508. }
  509.  
  510. static unsigned int crc;
  511.  
  512. short get2q();
  513. long get4q();
  514.  
  515. /* read header of .hqx file */
  516. do_q_header(macname)
  517. char *macname;
  518. {
  519.     char namebuf[256];        /* big enough for both att & bsd */
  520.     int n;
  521.     unsigned int calc_crc, file_crc;
  522.  
  523.     crc = 0;            /* compute a crc for the header */
  524.     q_init();            /* reset static variables */
  525.  
  526.     n = getq();            /* namelength */
  527.     n++;                /* must read trailing null also */
  528.     getqbuf(namebuf, n);        /* read name */
  529.     if (macname[0] == '\0')
  530.         macname = namebuf;
  531.  
  532.     n = strlen(macname);
  533.     if (n > NAMEBYTES)
  534.         n = NAMEBYTES;
  535.     strncpy(mh.m_name, macname, n);
  536.     mh.m_name[n] = '\0';
  537.  
  538.     getqbuf(mh.m_type, 4);
  539.     getqbuf(mh.m_author, 4);
  540.     mh.m_flags = get2q();
  541.     mh.m_datalen = get4q();
  542.     mh.m_rsrclen = get4q();
  543.  
  544.     comp_q_crc(0);
  545.     comp_q_crc(0);
  546.     calc_crc = crc;
  547.     file_crc = get2q();
  548.     /* no files no open at this point */
  549.     verify_crc(calc_crc, file_crc);
  550. }
  551.  
  552. do_q_fork(char *fname, long len, int dataFork)
  553. {
  554.     register int c, i;
  555.     unsigned int calc_crc, file_crc;
  556.  
  557. #ifdef    MPW
  558. #define    BSIZE 512
  559.     ParamBlockRec    pb;
  560.     register char    *p;
  561.     register int    count;
  562.     char            buf[BSIZE];
  563.     
  564.     c2pstr (fname);
  565.     pb.ioParam.ioCompletion = NULL;
  566.     pb.ioParam.ioNamePtr = fname;
  567.     pb.ioParam.ioVRefNum = 0;
  568.     pb.ioParam.ioVersNum = 0;
  569.     pb.ioParam.ioMisc = NULL;
  570.     pb.ioParam.ioPermssn = fsWrPerm;
  571.     
  572.     if (dataFork) {
  573.         if (PBOpen(&pb, FALSE) != noErr) {
  574.             fprintf(stderr, "trouble opening data fork\n");
  575.             exit (-1);
  576.         }
  577.     }
  578.     else {
  579.         if (PBOpenRF (&pb, FALSE) != noErr) {
  580.             fprintf(stderr, "trouble opening resource fork\n");
  581.             exit (-1);
  582.         }
  583.     }    
  584.     p2cstr (fname);
  585.     pb.ioParam.ioBuffer = &buf;
  586.     pb.ioParam.ioPosMode = fsAtMark;
  587.     pb.ioParam.ioPosOffset = 0L;
  588.     pb.ioParam.ioReqCount = BSIZE;
  589.     p = buf;
  590.     count = 0;
  591. #else    MPW
  592.     FILE *outf;
  593.  
  594.     outf = fopen(fname, "w");
  595.  
  596.     if (outf == NULL) {
  597.         perror(fname);
  598.         exit(-1);
  599.     }
  600. #endif    MPW
  601.  
  602.     crc = 0;    /* compute a crc for a fork */
  603.  
  604.     if (len)
  605.         for (i = 0; i < len; i++) {
  606.             if ((c = getq()) == EOF) {
  607.                 fprintf(stderr, "unexpected EOF\n");
  608.                 #ifdef    MPW
  609.                     PBClose(&pb, FALSE);
  610.                     FlushVol (NULL, 0);
  611.                 #else    MPW
  612.                     fclose(outf);
  613.                 #endif    MPW
  614.                 exit(2);
  615.             }
  616. #ifdef    MPW
  617.             *p++ = c;
  618.             count++;
  619.             if (count & 0x0F) SpinCursor(1);
  620.             if (count == BSIZE) {
  621.                 /* buffer full */
  622.                 (void) PBWrite (&pb, FALSE);
  623.                 count = 0;
  624.                 p = buf;
  625.             }
  626. #else    MPW                
  627.             fputc(c, outf);
  628. #endif    MPW
  629.         }
  630.  
  631.     comp_q_crc(0);
  632.     comp_q_crc(0);
  633.     calc_crc = crc;
  634.     file_crc = get2q();
  635. #ifdef    MPW
  636.     if (count != 0) {
  637.         /* write out the last block */
  638.         SpinCursor(1);
  639.         pb.ioParam.ioReqCount = count;
  640.         (void) PBWrite (&pb, FALSE);
  641.     }
  642.     PBClose(&pb, FALSE);
  643.     FlushVol (NULL, 0);
  644. #else    MPW
  645.     fclose(outf);
  646. #endif    MPW
  647.     /* check CRC: we've written out a duff block but it doesn't matter */
  648.     verify_crc(calc_crc, file_crc);
  649. }
  650.  
  651. /* verify_crc(); -- check if crc's check out */
  652. verify_crc(calc_crc, file_crc)
  653. unsigned int calc_crc, file_crc;
  654. {
  655.     calc_crc &= WORDMASK;
  656.     file_crc &= WORDMASK;
  657.  
  658.     if (calc_crc != file_crc) {
  659.         fprintf(stderr, "CRC error\n---------\n");
  660.         fprintf(stderr, "CRC in file:\t0x%x\n", file_crc);
  661.         fprintf(stderr, "calculated CRC:\t0x%x\n", calc_crc);
  662.         exit(3);
  663.     }
  664. }
  665.  
  666. static int eof;
  667. static char obuf[3];
  668. static char *op, *oend;
  669.  
  670. /* initialize static variables for q format input */
  671. q_init()
  672. {
  673.     eof = 0;
  674.     op = obuf;
  675.     oend = obuf + sizeof obuf;
  676. }
  677.  
  678. /* get2q(); q format -- read 2 bytes from input, return short */
  679. short
  680. get2q()
  681. {
  682.     register int c;
  683.     short value = 0;
  684.  
  685.     c = getq();
  686.     value = (c & BYTEMASK) << 8;
  687.     c = getq();
  688.     value |= (c & BYTEMASK);
  689.  
  690.     return value;
  691. }
  692.  
  693. /* get4q(); q format -- read 4 bytes from input, return long */
  694. long
  695. get4q()
  696. {
  697.     register int c, i;
  698.     long value = 0L;
  699.  
  700.     for (i = 0; i < 4; i++) {
  701.         c = getq();
  702.         value <<= 8;
  703.         value |= (c & BYTEMASK);
  704.     }
  705.     return value;
  706. }
  707.  
  708. /* getqbuf(); q format -- read n characters from input into buf */
  709. /*        All or nothing -- no partial buffer allowed */
  710. getqbuf(buf, n)
  711. register char *buf;
  712. register int n;
  713. {
  714.     register int c, i;
  715.  
  716.     for (i = 0; i < n; i++) {
  717.         if ((c = getq()) == EOF)
  718.             return EOF;
  719.         *buf++ = c;
  720.     }
  721.     return 0;
  722. }
  723.  
  724. #define RUNCHAR 0x90
  725.  
  726. /* q format -- return one byte per call, keeping track of run codes */
  727. getq()
  728. {
  729.     register int c;
  730.  
  731.     if ((c = getq_nocrc()) == EOF)
  732.         return EOF;
  733.     comp_q_crc((unsigned)c);
  734.     return c;
  735. }
  736.  
  737. getq_nocrc()
  738. {
  739.     static int rep, lastc;
  740.     int c;
  741.  
  742.     if (rep) {
  743.         rep--;
  744.         return lastc;
  745.     }
  746.     if ((c = getq_raw()) == EOF) {
  747.         return EOF;
  748.     }
  749.     if (c == RUNCHAR) {
  750.         if ((rep = getq_raw()) == EOF)
  751.             return EOF;
  752.         if (rep != 0) {
  753.             /* already returned one, about to return another */
  754.             rep -= 2;
  755.             return lastc;
  756.         }
  757.         else {
  758.             lastc = RUNCHAR;
  759.             return RUNCHAR;
  760.         }
  761.     }
  762.     else {
  763.         lastc = c;
  764.         return c;
  765.     }
  766. }
  767.  
  768. /* q format -- return next 8 bits from file without interpreting run codes */
  769. getq_raw()
  770. {
  771.     char ibuf[4];
  772.     register char *ip = ibuf, *iend = ibuf + sizeof ibuf;
  773.     int c;
  774.  
  775.     if (op == obuf) {
  776.         for (ip = ibuf; ip < iend; ip++) {
  777.             if ((c = get6bits()) == EOF)
  778.                 if (ip <= &ibuf[1])
  779.                     return EOF;
  780.                 else if (ip == &ibuf[2])
  781.                     eof = 1;
  782.                 else
  783.                     eof = 2;
  784.             *ip = (char)(c & BYTEMASK);
  785.         }
  786.         obuf[0] = (ibuf[0] << 2 | ibuf[1] >> 4);
  787.         obuf[1] = (ibuf[1] << 4 | ibuf[2] >> 2);
  788.         obuf[2] = (ibuf[2] << 6 | ibuf[3]);
  789.     }
  790.     if ((eof) & (op >= &obuf[eof]))
  791.         return EOF;
  792.     /*
  793.     fprintf (stderr, "c = %c %02x\n",
  794.                      (*op > ' ')? (*op & BYTEMASK) :'.',
  795.                      *op & BYTEMASK);
  796.     */
  797.     c = *op++;
  798.     if (op >= oend)
  799.         op = obuf;
  800.     return (c & BYTEMASK);
  801. }
  802.  
  803. /*
  804. char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  805.              0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  806.              0                1               2               3 
  807. trlookup is used to translate by direct lookup.  The input character
  808. is an index into trlookup.  If the result is 0xFF, a bad char has been read.
  809. Added by:  Dan LaLiberte, liberte@uiucdcs.Uiuc.ARPA, ihnp4!uiucdcs!liberte
  810. */
  811. char trlookup[83] = {     0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  812.             0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
  813.             0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
  814.             0x14, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  815.             0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
  816.             0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
  817.             0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
  818.             0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
  819.             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
  820.             0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
  821.             0x3D, 0x3E, 0x3F };
  822.  
  823. /* q format -- decode one byte into 6 bit binary */
  824. get6bits()
  825. {
  826.     register int c;
  827.     register int tc;
  828.  
  829.     while (1) {
  830.         c = fgetc(ifp) & BYTEMASK;
  831.         switch ((char)c) {
  832.         case '\n':
  833.         case '\r':
  834.             continue;
  835.         case ':':
  836.         case EOF:
  837.             return EOF;
  838.         default:
  839.             tc = c - (int)' ';
  840.              tc = (tc < 83) ? trlookup[tc] : 0xff;
  841. /*            fprintf(stderr, "c = '%c' %02x tc = %4x\n", c, c, tc);*/
  842.             if (tc != 0xff)
  843.                 return (tc);
  844.             fprintf(stderr, "bad char: '%c'\n", c);
  845.             return EOF;
  846.         }
  847.     }
  848. }
  849.  
  850.  
  851. #define CRCCONSTANT 0x1021
  852.  
  853. comp_q_crc(c)
  854. register unsigned int c;
  855. {
  856.     register int i;
  857.     register unsigned long temp = crc;
  858.  
  859.     for (i=0; i<8; i++) {
  860.         c <<= 1;
  861.         if ((temp <<= 1) & WORDBIT)
  862.             temp = (temp & WORDMASK) ^ CRCCONSTANT;
  863.         temp ^= (c >> 8);
  864.         c &= BYTEMASK;
  865.     }
  866.     crc = temp;
  867. }
  868.  
  869. /* old format -- process .hex and .hcx files */
  870. do_o_header(macname, filename)
  871. char *macname, *filename;
  872. {
  873.     char namebuf[256];        /* big enough for both att & bsd */
  874.     char ibuf[BUFSIZ];
  875.     int n;
  876.  
  877.     /* set up name for output files */
  878.     if (macname[0] == '\0') {
  879.         strcpy(namebuf, filename);
  880.  
  881.         /* strip directories */
  882.         macname = search_last(namebuf, '/');
  883.         if (macname == NULL)
  884.             macname = namebuf;
  885.         else
  886.             macname++;
  887.  
  888.         /* strip extension */
  889.         n = strlen(macname);
  890.         if (n > 4) {
  891.             n -= 4;
  892.             if (macname[n] == '.' && macname[n+1] == 'h'
  893.                         && macname[n+3] == 'x')
  894.                 macname[n] = '\0';
  895.         }
  896.     }
  897.     n = strlen(macname);
  898.     if (n > NAMEBYTES)
  899.         n = NAMEBYTES;
  900.     strncpy(mh.m_name, macname, n);
  901.     mh.m_name[n] = '\0';
  902.  
  903.     /* read "#TYPEAUTH$flag"  line */
  904.     if (fgets(ibuf, BUFSIZ, ifp) == NULL) {
  905.         fprintf(stderr, "unexpected EOF\n");
  906.         exit(2);
  907.     }
  908.     n = strlen(ibuf);
  909.     if (n >= 7 && ibuf[0] == '#' && ibuf[n-6] == '$') {
  910.         if (n >= 11)
  911.             strncpy(mh.m_type, &ibuf[1], 4);
  912.         if (n >= 15)
  913.             strncpy(mh.m_author, &ibuf[5], 4);
  914.         sscanf(&ibuf[n-5], "%4hx", &mh.m_flags);
  915.     }
  916. }
  917.  
  918. do_o_forks()
  919. {
  920.     char ibuf[BUFSIZ];
  921.     int forks = 0, found_crc = 0;
  922.     unsigned int calc_crc, file_crc;
  923.     extern long make_file();
  924. #ifdef    MPW
  925.     OSType    f_creator, f_type;
  926. #endif    MPW
  927.  
  928.  
  929.     crc = 0;    /* calculate a crc for both forks */
  930. #ifndef    MPW
  931.     /* create empty files ahead of time */
  932.     close(creat(files.f_data, 0666));
  933.     close(creat(files.f_rsrc, 0666));
  934. #else    MPW
  935.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  936.     BlockMove (mh.m_type, (char *)&f_type, 4);
  937.     (void)Create (mh.m_name, 0, f_creator, f_type);
  938. #endif    MPW
  939.  
  940.     while (!found_crc && fgets(ibuf, BUFSIZ, ifp) != NULL) {
  941.         if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
  942.             compressed++;
  943.             continue;
  944.         }
  945.         if (strncmp(ibuf, "***DATA", 7) == 0) {
  946.             mh.m_datalen = make_file(files.f_data, compressed);
  947.             forks++;
  948.             continue;
  949.         }
  950.         if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
  951.             mh.m_rsrclen = make_file(files.f_rsrc, compressed);
  952.             forks++;
  953.             continue;
  954.         }
  955.         if (compressed && strncmp(ibuf, "***CRC:", 7) == 0) {
  956.             found_crc++;
  957.             calc_crc = crc;
  958.             sscanf(&ibuf[7], "%x", &file_crc);
  959.             break;
  960.         }
  961.         if (!compressed && strncmp(ibuf, "***CHECKSUM:", 12) == 0) {
  962.             found_crc++;
  963.             calc_crc = crc & BYTEMASK;
  964.             sscanf(&ibuf[12], "%x", &file_crc);
  965.             file_crc &= BYTEMASK;
  966.             break;
  967.         }
  968.     }
  969.  
  970.     if (found_crc)
  971.         verify_crc(calc_crc, file_crc);
  972.     else {
  973.         fprintf(stderr, "missing CRC\n");
  974.         exit(3);
  975.     }
  976. }
  977.  
  978. long
  979. make_file(fname, compressed)
  980. char *fname;
  981. int compressed;
  982. {
  983.     char ibuf[BUFSIZ];
  984.     FILE *outf;
  985.     register long nbytes = 0L;
  986.  
  987.     outf = fopen(fname, "w");
  988.     if (outf == NULL) {
  989.         perror(fname);
  990.         exit(-1);
  991.     }
  992.  
  993.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  994.         if (strncmp(ibuf, "***END", 6) == 0)
  995.             break;
  996.         if (compressed)
  997.             nbytes += comp_to_bin(ibuf, outf);
  998.         else
  999.             nbytes += hex_to_bin(ibuf, outf);
  1000.     }
  1001.  
  1002.     fclose(outf);
  1003.     return nbytes;
  1004. }
  1005.  
  1006. comp_c_crc(c)
  1007. unsigned char c;
  1008. {
  1009.     crc = (crc + c) & WORDMASK;
  1010.     crc = ((crc << 3) & WORDMASK) | (crc >> 13);
  1011. }
  1012.  
  1013. comp_e_crc(c)
  1014. unsigned char c;
  1015. {
  1016.     crc += c;
  1017. }
  1018.  
  1019. #define SIXB(c) (((c)-0x20) & 0x3f)
  1020.  
  1021. comp_to_bin(ibuf, outf)
  1022. char ibuf[];
  1023. FILE *outf;
  1024. {
  1025.     char obuf[BUFSIZ];
  1026.     register char *ip = ibuf;
  1027.     register char *op = obuf;
  1028.     register int n, outcount;
  1029.     int numread, incount;
  1030.  
  1031.     numread = strlen(ibuf);
  1032.     ip[numread-1] = ' ';        /* zap out the newline */
  1033.     outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
  1034.     incount = ((outcount / 3) + 1) * 4;
  1035.     for (n = numread; n < incount; n++)    /* restore lost spaces */
  1036.         ibuf[n] = ' ';
  1037.  
  1038.     n = 0;
  1039.     while (n <= outcount) {
  1040.         *op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
  1041.         *op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
  1042.         *op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
  1043.         ip += 4;
  1044.         n += 3;
  1045.     }
  1046.  
  1047.     for (n=1; n <= outcount; n++)
  1048.         comp_c_crc((unsigned)obuf[n]);
  1049.  
  1050.     fwrite(obuf+1, 1, outcount, outf);
  1051.     return outcount;
  1052. }
  1053.  
  1054. hex_to_bin(ibuf, outf)
  1055. char ibuf[];
  1056. FILE *outf;
  1057. {
  1058.     register char *ip = ibuf;
  1059.     register int n, outcount;
  1060.     int c;
  1061.  
  1062.     n = strlen(ibuf) - 1;
  1063.     outcount = n / 2;
  1064.     for (n = 0; n < outcount; n++) {
  1065.         c = hexit(*ip++);
  1066.         comp_e_crc((unsigned)(c = (c << 4) | hexit(*ip++)));
  1067.         fputc(c, outf);
  1068.     }
  1069.     return outcount;
  1070. }
  1071.  
  1072. hexit(c)
  1073. int c;
  1074. {
  1075.     if ('0' <= c && c <= '9')
  1076.         return c - '0';
  1077.     if ('A' <= c && c <= 'F')
  1078.         return c - 'A' + 10;
  1079.  
  1080.     fprintf(stderr, "illegal hex digit: %c", c);
  1081.     exit(4);
  1082.     /* NOTREACHED */
  1083. }
  1084.  
  1085. put2(char *bp, short value)
  1086. {
  1087.     *bp++ = (value >> 8) & BYTEMASK;
  1088.     *bp++ = value & BYTEMASK;
  1089. }
  1090.  
  1091. put4(bp, value)
  1092. char *bp;
  1093. long value;
  1094. {
  1095.     register int i, c;
  1096.  
  1097.     for (i = 0; i < 4; i++) {
  1098.         c = (value >> 24) & BYTEMASK;
  1099.         value <<= 8;
  1100.         *bp++ = c;
  1101.     }
  1102. }
  1103.  
  1104.